package com.carey.blog.util;

import static com.carey.blog.model.Preference.PREFERENCE;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONException;
import org.json.JSONObject;

import com.carey.blog.framework.latke.cache.Cache;
import com.carey.blog.framework.latke.cache.CacheFactory;
import com.carey.blog.framework.latke.repository.RepositoryException;
import com.carey.blog.repository.PreferenceRepository;
import com.carey.blog.repository.impl.PreferenceGAERepository;

/**
 * Preference utilities.
 * 
 */
public final class Preferences {

	/**
	 * Preference cache.
	 */
	private static Cache<String, Object> userPreferenceCache;
	/**
	 * Preference repository.
	 */
	private PreferenceRepository preferenceRepository = PreferenceGAERepository
			.getInstance();
	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger.getLogger(Preferences.class
			.getName());
	/**
	 * Skin utilities.
	 */
	private Skins skins = Skins.getInstance();

	static {
		userPreferenceCache = CacheFactory.getCache(PREFERENCE);
	}

	/**
	 * Gets the user preference.
	 * 
	 * @return user preference, returns {@code null} if not found
	 */
	public JSONObject getPreference() {
		final Object preferenceString = userPreferenceCache.get(PREFERENCE);
		JSONObject ret = null;
		try {
			if (null == preferenceString) {
				LOGGER.info("Load preference from datastore");
				ret = preferenceRepository.get(PREFERENCE);

				if (null == ret) {
					return null;
				}

				skins.loadSkins(ret);

				setPreference(ret);
			} else {
				ret = new JSONObject(preferenceString.toString());
			}
		} catch (final Exception e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new RuntimeException(e);
		}

		return ret;
	}

	/**
	 * Sets the user preference with the specified preference in cache and
	 * repository.
	 * 
	 * @param preference
	 *            the specified preference
	 * @throws JSONException
	 *             json exception
	 * @throws RepositoryException
	 *             repository exception
	 */
	public void setPreference(final JSONObject preference)
			throws JSONException, RepositoryException {
		preferenceRepository.update(PREFERENCE, preference);
		userPreferenceCache.put(PREFERENCE, preference.toString());
	}

	/**
	 * Gets the {@link Preferences} singleton.
	 * 
	 * @return the singleton
	 */
	public static Preferences getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * Private default constructor.
	 */
	private Preferences() {
	}

	/**
	 * Singleton holder.
	 * 
	 */
	private static final class SingletonHolder {

		/**
		 * Singleton.
		 */
		private static final Preferences SINGLETON = new Preferences();

		/**
		 * Private default constructor.
		 */
		private SingletonHolder() {
		}
	}
}
